<%@ page import="javax.jcr.Repository,
         org.apache.jackrabbit.j2ee.RepositoryAccessServlet,
         org.apache.jackrabbit.util.Text,
         javax.jcr.Session,
         javax.jcr.SimpleCredentials,
         javax.jcr.query.Query,
         javax.jcr.query.RowIterator,
         java.text.NumberFormat,
         javax.jcr.query.Row,
         javax.jcr.Node,
         java.net.URLEncoder,
         java.text.SimpleDateFormat,
         java.text.DateFormat,
         java.util.List,
         java.util.ArrayList,
         java.util.Iterator,
         javax.jcr.Value,
         javax.jcr.RepositoryException,
         org.apache.commons.fileupload.*,
         org.apache.commons.fileupload.servlet.*,
         org.apache.commons.fileupload.disk.*,
         java.io.*,
         java.util.zip.*,
         javax.mail.internet.*,
         javax.mail.*,
         java.util.*,
         java.util.concurrent.Future,
         java.util.concurrent.Callable,
         org.apache.commons.io.IOUtils,
         java.net.*,
         org.ilookinto.jr.JCRStoreBean,
         org.ilookinto.util.NodeUtil,
         org.ilookinto.util.CloseUtil,
         org.ilookinto.jr.MetadataServlet
         "
         %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">

<%

    Session jcrSession = null;
    try {
      Repository rep;
      if (ServletFileUpload.isMultipartContent(request)) {
        try {
          rep = RepositoryAccessServlet.getRepository(pageContext.getServletContext());
          jcrSession = rep.login(new SimpleCredentials("admin", "admin".toCharArray()));
        } catch (Throwable e) {
          e.printStackTrace();
          return;
        }
        // Create a factory for disk-based file items
        FileItemFactory factory = new DiskFileItemFactory();
        // Create a new file upload handler
        ServletFileUpload upload = new ServletFileUpload(factory);

        //Create a progress listener
        final HttpSession myHttpSession = session;
        ProgressListener progressListener = new ProgressListener() {

          private long megaBytes = -1;

          public void update(long pBytesRead, long pContentLength, int pItems) {
            long mBytes = pBytesRead / 1000;
            if (megaBytes == mBytes) {
              return;
            }
            megaBytes = mBytes;
            myHttpSession.setAttribute("readed", pBytesRead + "");
            myHttpSession.setAttribute("length", pContentLength + "");
            //System.out.println("We are currently reading item " + pItems);
            if (pContentLength == -1) {
              System.out.println("So far, " + pBytesRead + " bytes have been read.");

            } else {
              System.out.println("So far, " + pBytesRead + " of " + pContentLength
                      + " bytes have been read.");
            }
          }
        };
        upload.setProgressListener(progressListener);

        java.util.List<FileItem> items = upload.parseRequest(request);
        Node root = jcrSession.getRootNode();

        Node folder = null;

        for (FileItem item : items) {
          String ct = item.getContentType();
          ct = ct.toLowerCase();

          javax.activation.MimetypesFileTypeMap m = new javax.activation.MimetypesFileTypeMap();
          out.println("ct=" + ct + ct.isEmpty() + item.getName());
          if (!ct.isEmpty()) {
            //Deal with zip file ....
            if (ct.contains("zip") && !ct.contains("gzip")) {
              processZipFile(item, root, session);
            } else if (item.getName().endsWith(".pst")) {
              processPstFile(item, NodeUtil.emailNode("testing", root), session);
            } //Deal with oridinary files.
            else {
              Node docRoot = NodeUtil.fileNodeFromURL(request.getRemoteAddr(), root);
              processDocFile(item, docRoot, session);
            }
          }
        }

        jcrSession.save();

        out.println("logout");
      } else {
        out.println("error");
      }
    } catch (Exception e) {
      e.printStackTrace();
      if (jcrSession != null) {
        jcrSession.logout();
      }
    }

%>


<%!  static org.apache.tika.mime.MimeTypes mt = new org.apache.tika.mime.MimeTypes();

  void processPstFile(FileItem item, Node emailRootNode, HttpSession session) throws Exception {
    processPstFile(item.getInputStream(), item.getName(), session);
  }

  void processPstFile(InputStream is, String fileName, HttpSession session) throws Exception {
    final File tempPst = new File("temp", fileName);
    IOUtils.copy(is, new FileOutputStream(tempPst));
    final String exePath = this.getServletContext().getRealPath("/") + "WEB-INF\\resources\\outlook\\pstToRepos";
    Future<String> result = MetadataServlet.es.submit(new Callable() {

      public String call() {
        try {
          ProcessBuilder pb = new ProcessBuilder(exePath, tempPst.getAbsolutePath());
          Process p = pb.start();
          final Scanner out = new Scanner(p.getInputStream());
          final Scanner error = new Scanner(p.getErrorStream());
          while (out.hasNextLine()) {
            System.out.println(out.nextLine());
          }
        } catch (Exception e) {
          return e.getMessage();
        }
        return "good";
      }
    });
  }

  void processDocFile(FileItem item, Node docRootNode, HttpSession session) throws Exception {
    session.setAttribute("fileName", item.getName());
    Node file = fileNodeFromURL(item.getName(), docRootNode);
    // out.println(file.getPath());
    if (file.hasNode("jcr:content")) {
      file.getNode("jcr:content").remove();
    }
    Node resource = file.addNode("jcr:content", "nt:resource");

    resource.setProperty("jcr:mimeType", mt.getMimeType(item.getName()).getName());

    resource.setProperty("jcr:data", item.getInputStream());
    java.util.Calendar lastModified = java.util.Calendar.getInstance();
    //lastModified.setTimeInMillis(item.);
    resource.setProperty("jcr:lastModified", lastModified);

  }

  void processZipFile(FileItem item, Node docRootNode, HttpSession session) throws Exception {
    ZipInputStream zis = new ZipInputStream(item.getInputStream());
    ZipEntry entry;
    while ((entry = zis.getNextEntry()) != null) {
      //out.println(entry.getName() + "<br/>");
      //Thread.currentThread().sleep(10000);
      if (entry.isDirectory() || entry.getName() == null) {
        continue;
      }
      String entryName = entry.getName().toLowerCase();
      if (entryName.endsWith(".zip")) {
        //processZipFile(null, docRootNode, session );
      } else if (entryName.endsWith(".pst")) {
        processPstFile(zis, entry.getName(), session);
      } else {
        session.setAttribute("fileName", entry.getName());
        Node file = fileNodeFromURL(entry.getName(), docRootNode);
        if (file.hasNode("jcr:content")) {
          file.getNode("jcr:content").remove();
        }
        Node resource = file.addNode("jcr:content", "nt:resource");
        resource.setProperty("jcr:mimeType", mt.getMimeType(entry.getName()).getName());

        if (entry.getSize() < 1024 * 1024 * 10) {
          java.io.ByteArrayInputStream b = new ByteArrayInputStream(org.apache.commons.io.IOUtils.toByteArray(zis));
          resource.setProperty("jcr:data", b);
        } else {
          File t1 = File.createTempFile("temp", null);
          FileOutputStream fos = new FileOutputStream(t1);
          org.apache.commons.io.IOUtils.copy(zis, fos);
          fos.close();
          FileInputStream fis = new FileInputStream(t1);
          resource.setProperty("jcr:data", fis);
          t1.delete();
        }
        java.util.Calendar lastModified = java.util.Calendar.getInstance();
        lastModified.setTimeInMillis(entry.getTime());
        resource.setProperty("jcr:lastModified", lastModified);

        System.out.println(entry.getName() + mt.getMimeType(entry.getName()));
      }
    }
  }
  // The following is deprecated.

  void processPstFileWithCopyingToImapFolder(FileItem item, Node emailRootNode,
          HttpSession session) throws Exception {
    File tempPst = new File("temp", item.getName());
    IOUtils.copy(item.getInputStream(), new FileOutputStream(tempPst));
    Properties props = new Properties();
    // props.put("mail.from", "user2@mailserver.com");
    javax.mail.Session emailSession = javax.mail.Session.getInstance(props);
    final Store store = emailSession.getStore("imap");
    store.connect("localhost", "elookinto", "elookinto");
    String folderName = item.getName().substring(item.getName().lastIndexOf(File.separator) + 1, item.getName().lastIndexOf("."));

    Folder folder = null;
    try {
      folder = store.getDefaultFolder().getFolder(folderName);
      folder.delete(true);
    } catch (Exception e) {
    }
    String exePath = this.getServletContext().getRealPath("/") + "WEB-INF\\resources\\outlook\\pstToRepos";
    ProcessBuilder pb = new ProcessBuilder(exePath, tempPst.getAbsolutePath());
    Process p = pb.start();
    final Scanner out = new Scanner(p.getInputStream());
    final Scanner error = new Scanner(p.getErrorStream());
    while (out.hasNextLine()) {
      System.out.println(out.nextLine());
    }
    //p.wait();
    folder = store.getDefaultFolder().getFolder(folderName);
    processMessage(folder, session, emailRootNode);
    folder.delete(true);

  }

  private void processMessage(Folder folder, javax.servlet.http.HttpSession session, Node emailRootNode) {
    if ("true".equals(session.getAttribute("cancel"))) {
      return;
    }

    try {
      JCRStoreBean jcrStoreBean = new JCRStoreBean();
      jcrStoreBean.setParentNode(emailRootNode);
      folder.open(Folder.READ_ONLY);
      // folder.getMessage(345);
      int count = folder.getMessageCount();
      for (int i = 1; i <= count; i++) {
        if ("true".equals(session.getAttribute("cancel"))) {
          session.setAttribute("mm", "process status: cancelled;" + folder.getFullName() + ";" + i + " of total " + folder.getMessageCount() + " processed <br/>");
          break;
        }
        try {
          Message m = folder.getMessage(i);
          jcrStoreBean.storeMessage(m);
          System.out.println(i + " " + m.getSubject());

          if (i % 10 == 0 || i == count) {
            session.setAttribute("mm", "process status:" + session.getAttribute("cancel") + ";" + folder.getFullName() + ";" + i + " of total " + folder.getMessageCount() + "<br/>" + m.getSubject());
          }

        } catch (Exception e) {
          e.printStackTrace();
          break;
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      CloseUtil.close(folder);
    }
    try {
      Folder list[] = folder.list();
      for (Folder f : list) {
        processMessage(f, session, emailRootNode);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  static Node fileNodeFromURL(String sUrl, Node root) throws Exception {
    // final URL currentURL = urls[i];
    // root.getNodes().hasNext() root.getNodes().nextR;

    String path = "";// urls[i].getPath();

    String host = "";
    if (!path.startsWith("http")) {
      path = sUrl;
    } else {
      URL url = new URL(sUrl);
      host = url.getHost();
    }
    List folderNames = new ArrayList();
    if (!host.isEmpty()) {
      folderNames.addAll(Arrays.asList(host.split("\\.")));
    }
    Collections.reverse(folderNames);
    if (!path.isEmpty()) {
      folderNames.addAll(Arrays.asList(path.split("/|\\\\")));
    }
    final String fileName = URLDecoder.decode((String) folderNames.remove(folderNames.size() - 1), "UTF-8").replaceAll(":", "_");
    System.out.println(folderNames);
    System.out.println(fileName);
    Node node = root;
    for (Iterator fn = folderNames.iterator(); fn.hasNext();) {
      String name = URLDecoder.decode((String) fn.next(), "UTF-8");
      name = name.replaceAll(":", "_");
      if (name.length() == 0) {
        continue;
      }
      if (!node.hasNode(name)) {
        node.addNode(name, "nt:folder");
        //System.out.println("added name=" + name);
      }
      node = node.getNode(name);
    }
    final Node file;
    if (!node.hasNode(fileName)) {
      file = node.addNode(fileName, "nt:file");
    } else {
      file = node.getNode(fileName);
    }
    return file;
  }
%>